/*****************************************************************************
 * This file contains functions for compression / decompression
 *
*****************************************************************************/
#include <vector>
#include <math.h>

#include <sys/time.h>
#include <string.h>
#include "cache.h"
#include "transaction.h"
#include "globals.h"
#include "sim_engine.h"

#define ZERO                   0x00000000
#define MASK_HALF_BYTE         0x0000000F
#define MASK_BYTE              0x000000FF
#define MASK_HALF_WORD         0x0000FFFF
#define SHIFT_HALF_BYTE        4
#define SHIFT_BYTE             8
#define SHIFT_HALF_WORD        16
#define PREFIX                 3

//long long compress_fvc(TRANSTYPE *tr)
//{
//  long long cycle_delay = 0;
//  int bits = 0, uncomp =0;
//  int j = 0, zend=0;

//  tr->linesize = 0;
//  compress_count++;

//  /*printf("%llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx %llx\n", 
//    (tr->data[0]), (tr->data[1]), (tr->data[2]),(tr->data[3]),
//    (tr->data[4]), (tr->data[5]), (tr->data[6]),(tr->data[7]),
//    (tr->data[8]), (tr->data[9]), (tr->data[10]),(tr->data[11]),
//    (tr->data[12]), (tr->data[13]), (tr->data[14]),(tr->data[15]));
//    */

//  for(int i = 0; i<16; i++)
//  {

//    long long first_word = tr->data[i] & MASK_HALF_WORD;
//    long long second_word = (tr->data[i] & ~MASK_HALF_WORD)>> SHIFT_HALF_WORD;

//    if(i+8 > 16)
//      zend = 16;
//    else
//      zend = i + 8;

//    for(j = i; j < zend ; j++)
//    {
//      //      printf("j running @ %d\n",j);
//      if(tr->data[j] != ZERO)
//        break;
//    }
//    // Zero run
//    if(tr->data[i] == ZERO)
//    {
//      bits += PREFIX + 3;
//      pattern_zero+=j-i;
//      //printf("Zero Run word %d starting at %d ending at %d\n",j-i,i,j);
//      i = j;
//    }

//    // 4-bit sign extended
//    else if((tr->data[i] >> SHIFT_HALF_BYTE) == ZERO || 
//        (tr->data[i] | MASK_HALF_BYTE) == ~ZERO )
//    {
//      bits += PREFIX + 1 + 4 ;
//      //printf("4 bit SE word starting at %d\n",i);
//      pattern_4b_se++;
//    }
//    // 8-bit sign extended
//    else if((tr->data[i] >> SHIFT_BYTE) == ZERO || 
//        (tr->data[i] | MASK_BYTE) == ~ZERO )
//    {
//      bits += PREFIX + 1 + 8;
//      //printf("8 bit SE word starting at %d\n",i);
//      pattern_8b_se++;
//    }
//    // 16-bit sign extended
//    else if((tr->data[i] >> SHIFT_HALF_WORD) == ZERO || 
//        (tr->data[i] | MASK_HALF_WORD) == ~ZERO )
//    {
//      bits += PREFIX + 1 + 16; 
//      //printf("16 bit SE word starting at %d\n",i);
//      pattern_16b_se++;
//    }

//    // Half word padded with zero
//    else if((tr->data[i] & MASK_HALF_WORD) == ZERO)
//    {
//      bits += PREFIX + 16;
//      //printf("16 bit padded word starting at %d\n",i);
//      pattern_16b_padded++;
//    }

//    // Two Halfwords each sign extended 
//    else if( ((first_word >> SHIFT_BYTE) == ZERO || 
//          (first_word | MASK_BYTE) == ~ZERO ) && 
//        ((second_word >> SHIFT_BYTE) == ZERO || 
//         (second_word | MASK_BYTE) == ~ZERO) )
//    {
//      bits += PREFIX + 16 + 2;
//      //printf("16 bit each SE word starting at %d\n",i);
//      pattern_16b_se_half++;
//    }
//    // Repeated bytes
//    else if((first_word == second_word ) && 
//        ((first_word >> SHIFT_BYTE) == (first_word & MASK_BYTE)))
//    {
//      bits += PREFIX + 8;
//      //printf("8 bit repeated word starting at %d\n",i);
//      pattern_8b_rep++;
//    }
//    // The word as it is
//    else
//    {
//      bits += PREFIX + 32;
//      //printf("32 bit uncompressed word starting at %d\n",i);
//      pattern_32b++;
//      uncomp++;
//    }
//  }

//  if(COMPRESS_NOX)
//  {
//    tr->noxlinesize = (short)ceil(bits/32.0);
//    if(uncomp == 16)
//      tr->noxlinesize = 16;
//    cycle_delay = COMPRESSION_LATENCY ;
//  }

//  if(COMPRESS_CSIM)
//  {
//    tr->linesize = (short)ceil(bits/32.0);
//    if(uncomp == 16)
//      tr->linesize = 16;
//    cycle_delay = COMPRESSION_LATENCY ;
//  }
//  else
//  {
//    tr->linesize = llc_linesize/SET_SEG_SIZE;
//    cycle_delay = 0;
//  }

//  //printf("bits :%d\n",tr->linesize);

//  if (tr->linesize > 18)
//    printf("ERR : wrong fvc bits!!! %s\n",__func__);

//  compress_linesize += tr->linesize;

//  return cycle_delay;

//}


short fetch_csize(long long data[16])
{
  long long cycle_delay = 0;

  int j = 0;
  int bits = 0, uncomp =0;

  compress_count++;
  short linesize = 0;

  for(int i = 0; i<16; i++)
  {

    long long first_word = data[i] & MASK_HALF_WORD;
    long long second_word = (data[i] & ~MASK_HALF_WORD)>> SHIFT_HALF_WORD;

    for(j = i; j < (i+8 > 16) ? 16:i+8 ; j++)
    {
      if(data[j] != ZERO)
        break;
    }
    // Zero run
    if(data[i] == ZERO)
    {
      bits += PREFIX + 3;
      //pattern_zero+=j-i;
      i = j;
    }

    // 4-bit sign extended
    else if((data[i] >> SHIFT_HALF_BYTE) == ZERO || 
        (data[i] | MASK_HALF_BYTE) == ~ZERO )
      bits += PREFIX + 1 + 4 ;

    // 8-bit sign extended
    else if((data[i] >> SHIFT_BYTE) == ZERO || 
        (data[i] | MASK_BYTE) == ~ZERO )
      bits += PREFIX + 1 + 8;

    // 16-bit sign extended
    else if((data[i] >> SHIFT_HALF_WORD) == ZERO || 
        (data[i] | MASK_HALF_WORD) == ~ZERO )
      bits += PREFIX + 1 + 16;  

    // Half word padded with zero
    else if((data[i] & MASK_HALF_WORD) == ZERO)
      bits += PREFIX + 16;  

    // Two Halfwords each sign extended 
    else if( ((first_word >> SHIFT_BYTE) == ZERO || 
          (first_word | MASK_BYTE) == ~ZERO ) && 
        ((second_word >> SHIFT_BYTE) == ZERO || 
         (second_word | MASK_BYTE) == ~ZERO) )
      bits += PREFIX + 16 + 2;
    // Repeated bytes
    else if((first_word == second_word ) && 
        ((first_word >> SHIFT_BYTE) == (first_word & MASK_BYTE)))
      bits += PREFIX + 3;
    // The word as it is
    else
    {
      uncomp++;
      bits += PREFIX + 32;
    }
  }
  if(COMPRESS_CSIM)
  {
    linesize = (short)ceil(bits/32.0);
    if(uncomp == 16)
      linesize = 16;
    cycle_delay = COMPRESSION_LATENCY ;
  }
  else
  {
    linesize = llc_linesize/SET_SEG_SIZE;
    cycle_delay = 0;
  }
  if(COMPRESS_NOX)
  {
    linesize = (short)ceil(bits/32.0);
    if(uncomp == 16)
      linesize = 16;
    cycle_delay = COMPRESSION_LATENCY ;
  }

  if (linesize > 18)
    printf("ERR : wrong fvc bits!!! %s\n",__func__);

  compress_linesize += linesize;

  return linesize;

}
